package com.xbongbong.saas.service.impl;

import com.alibaba.fastjson.JSONObject;
import com.xbongbong.paas.constant.PaasConstant;
import com.xbongbong.paas.domain.entity.PaasFormDataEntity;
import com.xbongbong.paas.domain.entity.ext.ConditionsEntityExt;
import com.xbongbong.paas.domain.entity.ext.PaasFormDataEntityExt;
import com.xbongbong.paas.elasticsearch.model.PaasEsModel;
import com.xbongbong.paas.elasticsearch.pojo.XbbAggregatedPage;
import com.xbongbong.paas.elasticsearch.pojo.dto.InsertDTO;
import com.xbongbong.paas.elasticsearch.util.EsHelper;
import com.xbongbong.paas.elasticsearch.util.EsUtil;
import com.xbongbong.paas.elasticsearch.util.XbbElasticsearchRestTemplate;
import com.xbongbong.paas.enums.BelongEnum;
import com.xbongbong.paas.enums.ConditionEnum;
import com.xbongbong.paas.enums.DelEnum;
import com.xbongbong.paas.enums.FieldTypeEnum;
import com.xbongbong.paas.enums.IndexTypeEnum;
import com.xbongbong.paas.field.FieldAttrEntity;
import com.xbongbong.paas.help.subform.TransferSubFormHelper;
import com.xbongbong.paas.pojo.dto.FormDataListDTO;
import com.xbongbong.paas.pojo.dto.PaasFormDataEsMappingDTO;
import com.xbongbong.paas.pojo.vo.PaasFormDataEsListVO;
import com.xbongbong.paas.toolbox.exception.XbbException;
import com.xbongbong.paas.toolbox.helper.PageHelper;
import com.xbongbong.paas.toolbox.util.BeanUtil;
import com.xbongbong.paas.toolbox.util.CloneUtil;
import com.xbongbong.paas.toolbox.util.StringUtil;
import com.xbongbong.pro.constant.BusinessConstant;
import com.xbongbong.pro.constant.ElasticConstant;
import com.xbongbong.pro.enums.errorcodes.SystemErrorCodeEnum;
import com.xbongbong.saas.constant.StringConstant;
import com.xbongbong.saas.domain.entity.ProductWarehouseEntity;
import com.xbongbong.saas.enums.XbbRefTypeEnum;
import com.xbongbong.saas.enums.business.ProductEnum;
import com.xbongbong.saas.enums.subform.ProductWarehouseSubFormEnum;
import com.xbongbong.saas.model.IndexTypeModel;
import com.xbongbong.saas.model.ProductWarehouseModel;
import com.xbongbong.saas.service.ProductWarehouseService;
import org.elasticsearch.action.search.SearchRequest;
import org.elasticsearch.action.support.WriteRequest;
import org.elasticsearch.index.query.BoolQueryBuilder;
import org.elasticsearch.join.query.HasParentQueryBuilder;
import org.elasticsearch.join.query.JoinQueryBuilders;
import org.elasticsearch.search.builder.SearchSourceBuilder;
import org.elasticsearch.search.sort.FieldSortBuilder;
import org.elasticsearch.search.sort.SortOrder;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.data.domain.PageRequest;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Set;

import static org.elasticsearch.index.query.QueryBuilders.boolQuery;
import static org.elasticsearch.index.query.QueryBuilders.termQuery;
import static org.elasticsearch.index.query.QueryBuilders.termsQuery;

/**
 * @author Jian.Wang
 * @date  2019-01-28 9:24
 **/
@Service("ProductWarehouseService")
public class ProductWarehouseServiceImpl implements ProductWarehouseService{

    private static final Logger LOG = LoggerFactory.getLogger(ProductWarehouseServiceImpl.class);

    @Resource
    private ProductWarehouseModel productWarehouseModel;
    @Resource
    private PaasEsModel paasEsModel;
    @Resource
    private XbbElasticsearchRestTemplate xbbElasticsearchRestTemplate;
    @Resource
    private EsHelper esHelper;
    @Resource
    private TransferSubFormHelper transferSubFormHelper;
    @Resource
    private IndexTypeModel indexTypeModel;

    @Override
    public Integer deleteByProductIdIn(String corpid, List<Long> productIdIn) throws XbbException {
        return productWarehouseModel.deleteByProductIdIn(corpid, productIdIn);
    }
    @Override
    public ProductWarehouseEntity getByKey(Integer key, String corpid) {
        return productWarehouseModel.getByKey(key, corpid);
    }

    @Override
    public Integer getEntitysCount(Map<String, Object> param) {
        return productWarehouseModel.getEntitysCount(param);
    }

    @Override
    public void dataConsistencyUpdateWarehouse(String corpid, Long dataId, String name) {
        try {
            productWarehouseModel.updateWarehouseNameByWarehouseId(name,corpid,dataId);
            Map<String, Object> param = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
            param.put("corpid", corpid);
            param.put("warehouseId", dataId);
            param.put("del", 0);
            List<ProductWarehouseEntity> productWarehouseEntityList = productWarehouseModel.findEntitysWithWarehouseChecked(param,null);
            for (ProductWarehouseEntity entity : productWarehouseEntityList) {
                entity.setWarehouseName(name);
            }
            if (productWarehouseEntityList.size() > 0) {
                List<InsertDTO> updateDTOList = new ArrayList<>();
                Map<String, Object> map = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
                JSONObject object = new JSONObject();
                object.put(ProductWarehouseSubFormEnum.WAREHOUSE_NAME.getDataAttr(), name);
                map.put(StringConstant.JSON_DATA, object);
                for (ProductWarehouseEntity productWarehouse : productWarehouseEntityList){
                    InsertDTO insertDTO = new InsertDTO();
                    insertDTO.setWaitUntil(WriteRequest.RefreshPolicy.NONE);
                    insertDTO.setEsId(IndexTypeEnum.IDX_SAAS_PRODUCT_WAREHOUSE.getType() + "_" + productWarehouse.getCorpid() + "_" + productWarehouse.getId());
                    insertDTO.setParent(productWarehouse.getCorpid() + "_" + productWarehouse.getProductId());
                    insertDTO.setIndexTypeEnum(IndexTypeEnum.IDX_SAAS_PRODUCT_WAREHOUSE);
                    insertDTO.setSource(map);
                    updateDTOList.add(insertDTO);
                }
                paasEsModel.updateBatch(updateDTOList);
            }
        } catch (Exception e) {
            LOG.error("ProductWarehouseServiceImpl.dataConsistencyUpdateWarehouse 出错， corpid=" + corpid + "  warehouseId=" + dataId + "  warehouseName=" + name, e);
        }
    }

    @Override
    public PaasFormDataEsListVO warningSearchList(FormDataListDTO formDataListDTO) throws XbbException {
        PaasFormDataEsListVO formDataListVO = new PaasFormDataEsListVO();
        try {
            SearchSourceBuilder sourceBuilder = new SearchSourceBuilder();
            BoolQueryBuilder parentBoolQueryBuilder = boolQuery();
            parentBoolQueryBuilder.filter(termQuery("corpid.keyword",formDataListDTO.getCorpid()));
            parentBoolQueryBuilder.filter(termQuery(StringConstant.DEL, DelEnum.NORMAL.getDel()));
            parentBoolQueryBuilder.mustNot(termQuery(ProductEnum.getEsAttr4Keyword(ProductEnum.PARENT_ID),0));
            EsUtil.parseShouldCondition(parentBoolQueryBuilder,formDataListDTO.getShouldConditions(),"",formDataListDTO.getCorpid(), XbbRefTypeEnum.PRODUCT.getCode());
            List<ConditionsEntityExt> conditionsEntityExtList = new ArrayList<>();
            formDataListDTO.getConditions().removeIf(item -> Objects.equals(item.getAttr(), ProductEnum.WAREHOUSE.getAttr()));
            if (!formDataListDTO.getSelectWarehouseIdList().isEmpty()) {
                conditionsEntityExtList.add(new ConditionsEntityExt(ProductWarehouseSubFormEnum.getEsAttr(ProductWarehouseSubFormEnum.WAREHOUSE_ID),"",FieldTypeEnum.STOCK_WAREHOUSE_ID.getType(), ConditionEnum.IN.getSymbol(),new ArrayList<>(formDataListDTO.getSelectWarehouseIdList())));
            }
            List<ConditionsEntityExt> conditions = formDataListDTO.getConditions();
            ConditionsEntityExt conditionsEntityExt = null;
            for (ConditionsEntityExt condition : conditions) {
                if (Objects.equals(ProductEnum.NAME.getAttr(), condition.getAttr())) {
                    conditionsEntityExt= condition;
                }
            }
            conditions.remove(conditionsEntityExt);
            if (Objects.nonNull(conditionsEntityExt)) {
                parentBoolQueryBuilder.filter(termsQuery(BusinessConstant.ID, conditionsEntityExt.getValue()));
            }
            EsUtil.parseCondition(parentBoolQueryBuilder,formDataListDTO.getConditions(),"",formDataListDTO.getCorpid(),XbbRefTypeEnum.PRODUCT.getCode());
            EsUtil.setProductNameLike(formDataListDTO.getNameLike(),null,parentBoolQueryBuilder,true);
            BoolQueryBuilder boolQueryBuilder = boolQuery();
            boolQueryBuilder.filter(termQuery("corpid.keyword",formDataListDTO.getCorpid()));
            boolQueryBuilder.filter(termQuery(StringConstant.DEL, DelEnum.NORMAL.getDel()));
            conditionsEntityExtList.add(new ConditionsEntityExt(ProductWarehouseSubFormEnum.getEsAttr(ProductWarehouseSubFormEnum.IS_NOTIFY),"",FieldTypeEnum.WAREHOUSE_IS_NOTIFY.getType(),ConditionEnum.EQUAL.getSymbol(), Collections.singletonList(1)));
            conditionsEntityExtList.add(new ConditionsEntityExt(ProductWarehouseSubFormEnum.getEsAttr(ProductWarehouseSubFormEnum.WAREHOUSE_CHECKED),"",FieldTypeEnum.WAREHOUSE_CHECKED.getType(),ConditionEnum.EQUAL.getSymbol(),Collections.singletonList(1)));
            //解析查询条件
            IndexTypeEnum indexTypeEnum = IndexTypeEnum.IDX_SAAS_PRODUCT_WAREHOUSE;
            EsUtil.parseCondition(boolQueryBuilder,conditionsEntityExtList,formDataListDTO.getRel(),formDataListDTO.getCorpid(),formDataListDTO.getBusinessType());
            //解析或条件
            EsUtil.parseProductSearchCondition(boolQueryBuilder,formDataListDTO.getProductSerchConditions(),formDataListDTO.getRel(),formDataListDTO.getCorpid(),formDataListDTO.getSubBusinessType());
            HasParentQueryBuilder hasParentQueryBuilder = JoinQueryBuilders.hasParentQuery(IndexTypeEnum.IDX_SAAS_PRODUCT.getType(), parentBoolQueryBuilder, false);
            boolQueryBuilder.filter(hasParentQueryBuilder);
            //设置查询路由
            PaasFormDataEsMappingDTO paasFormDataEsMappingDTO = new PaasFormDataEsMappingDTO();
            BeanUtil.copyProperties(formDataListDTO,paasFormDataEsMappingDTO);

            boolQueryBuilder.filter(termQuery(ElasticConstant.MY_JOIN_FIELD, indexTypeEnum.getType()));
            sourceBuilder.query(boolQueryBuilder);
            if (Objects.equals(2, formDataListDTO.getFromExport()) && Objects.nonNull(formDataListDTO.getSearchAfterList()) && formDataListDTO.getSearchAfterList().length>0) {
                // 导出数据的游标
                sourceBuilder.searchAfter(formDataListDTO.getSearchAfterList());
            }
            //排序
            SortOrder order = SortOrder.DESC;
            String sortField = "updateTime";
            Map<String, String> sortMap = formDataListDTO.getSortMap();
            if(sortMap != null && !sortMap.isEmpty()){
                sortField = (StringUtil.isEmpty(sortMap.get("field")) ? sortField : sortMap.get("field"));
                Map<String, FieldAttrEntity> explainMap = formDataListDTO.getExplainMap();
                if(explainMap.containsKey(sortField)){
                    String raw = ".raw";
                    FieldAttrEntity sortFieldEntity = explainMap.get(sortField);
                    FieldTypeEnum fieldTypeEnum = FieldTypeEnum.getFieldTypeEnum(sortFieldEntity.getFieldType());
                    if(FieldTypeEnum.TEXT.getEsalias().equals(fieldTypeEnum.getEsalias())){
                        sortField = sortField + raw;
                    }
                    //系统字段不用加data.
                    if (!BelongEnum.SYSTEM.getAlias().equals(fieldTypeEnum.getBelong())) {
                        sortField = "data." + sortField;
                    }else if (Objects.equals(fieldTypeEnum.getType(),FieldTypeEnum.SERIALNO.getType()) && !sortField.contains(fieldTypeEnum.getAlias())){
                        sortField = "data." + sortField;
                    }
                } else {
                    // 排序不存在字段列表中时，给定默认排序，以防报错
                    sortField = "updateTime";
                }
                if(SortOrder.ASC.toString().equals(sortMap.get("sort"))){
                    order = SortOrder.ASC;
                }
            }
            sourceBuilder.sort(new FieldSortBuilder(sortField).order(order));
            //限定返回值
            List<String> fieldList = formDataListDTO.getFieldList();
            EsUtil.setFieldList(sourceBuilder, fieldList);
            //分页
            Integer page = formDataListDTO.getPage();
            Integer pageSize = formDataListDTO.getPageSize();
            PageRequest pageRequest= EsUtil.setPage(sourceBuilder, page, pageSize);
            SearchRequest searchRequest = new SearchRequest(indexTypeEnum.getIndex());
            searchRequest.source(sourceBuilder);
            String prefix = "------------------listByEs------------------:";
            long num;
            List<ProductWarehouseEntity> productWarehouseEntities;
            List<PaasFormDataEntity> list;
            Object[] sortValue = new Object[]{};
            if (Objects.equals(formDataListDTO.getFromExport(), 1)) {
                list = xbbElasticsearchRestTemplate.getScrollListForExport(PaasFormDataEntity.class, searchRequest);
                productWarehouseEntities = transferSubFormHelper.transferFormDataToProductWarehouseList(list);
                num = productWarehouseEntities.size();
            } else {
                XbbAggregatedPage<PaasFormDataEntity> esEntities = xbbElasticsearchRestTemplate.queryForPages(pageRequest, searchRequest, PaasFormDataEntity.class);
                if (esEntities == null) {
                    throw new XbbException(SystemErrorCodeEnum.API_ERROR_100001, SystemErrorCodeEnum.API_ERROR_100001.getMsg());
                }
                list = esEntities.getContent();
                productWarehouseEntities = transferSubFormHelper.transferFormDataToProductWarehouseList(list);
                num = esEntities.getTotalElements();
                sortValue = esEntities.getSortValue();
            }
            List<PaasFormDataEntityExt> resultList = new ArrayList<>();
            Set<Long> productIdSet = new HashSet<>();
            productIdSet.add(-1L);
            for (ProductWarehouseEntity productWarehouseEntity : productWarehouseEntities) {
                productIdSet.add(productWarehouseEntity.getProductId());
            }
            boolQueryBuilder = boolQuery();
            boolQueryBuilder.filter(termQuery("corpid.keyword",formDataListDTO.getCorpid()));
            boolQueryBuilder.filter(termQuery(StringConstant.DEL,DelEnum.NORMAL.getDel()));
            boolQueryBuilder.filter(termsQuery(FieldTypeEnum.DATAID.getAlias(), productIdSet));
            List<PaasFormDataEntityExt> paasFormDataEntityExtList = esHelper.findByScroll(IndexTypeEnum.IDX_SAAS_PRODUCT,boolQueryBuilder,PaasFormDataEntityExt.class, null);
            Map<Long, PaasFormDataEntityExt> productEntityMap = new HashMap<>();
            paasFormDataEntityExtList.forEach(item -> productEntityMap.put(item.getDataId(), item));
            for (ProductWarehouseEntity productWarehouseEntity : productWarehouseEntities) {
                if (productEntityMap.containsKey(productWarehouseEntity.getProductId())) {
                    PaasFormDataEntityExt paasFormDataEntityExt = (PaasFormDataEntityExt) CloneUtil.deepClone(productEntityMap.get(productWarehouseEntity.getProductId()));
                    paasFormDataEntityExt.setProductWarehouseEntity(productWarehouseEntity);
                    paasFormDataEntityExt.setTagData(new JSONObject());
                    resultList.add(paasFormDataEntityExt);
                }
            }
            PageHelper pageHelper = new PageHelper(page, pageSize);
            pageHelper.setRowsCount((int) num);
            formDataListVO.setPaasFormDataESList(resultList);
            formDataListVO.setPageHelper(pageHelper);
            formDataListVO.setBusinessType(formDataListDTO.getBusinessType());
            formDataListVO.setSortValue(sortValue);
        } catch (Exception e) {
            LOG.error("es查询出错",e);
            throw new XbbException(SystemErrorCodeEnum.API_ERROR_100001, SystemErrorCodeEnum.API_ERROR_100001.getMsg());
        }
        return formDataListVO;
    }

}
